// 获取类型
import type {
  IState,
  IAnyFunctionObject,
  IObjectOrArray,
  IStateCreateOption
} from '../types/type'

import type { InjectionKey } from 'vue'

// 基类类型，便于返回值带上类型
import type BaseArray from '../base2/base-array'
import type BaseObject from '../base2/base-object'

import { isReactive, provide } from 'vue'

// 状态的容器
import { store } from './store'

// 获取 两种状态形式，带 getter、actions，-- 纯 state的两种。
import OptionState from '../base2/option-state'

import { reBaseObject, reBaseArray } from './useStore'

/**
 * 单独定义状态，可以是全局状态，也可以是局部状态
 * @param id 标识（string | symbol），全局状态不能重名；局部状态可以重名。
 * @param info 状态，四种情况
 * * info：
 * * 一：函数：setup 风格
 * * 二：reactive、readonly，直接存入状态
 * * 三：对象：含有 state 属性 -- option 风格
 * * 四：对象：无 state 属性 -- 直接视为 state，option 风格
 * @param isLocal Boolean 默认是局部状态
 */
export default function defineStore<T extends IObjectOrArray> (
    id: symbol | string,
    info: IStateCreateOption | IAnyFunctionObject | IObjectOrArray,
    isLocal = true
  ) {
    
    // 判断ID是否重复
    if (isLocal) {
      // 局部状态，可以重复
    } else {
      // 全局状态，ID 如果重复 返回ID对应的状态
      if (store[id]) {
        if ((store[id] as IState ).$isObject) {
          return reBaseObject<T>(store[id])
        }
        if ((store[id] as IState ).$isArray) {
          return reBaseArray<T>(store[id])
        }
        return store[id] as T
      }
    }

    // 创建状态：
    /**
     * 1. 函数——setup；
     * 2. reactive —— 自定义；
     * 3. 对象（state）—— option；
     * 3.1. 对象 —— 全是state
     */

    // setup 风格，执行函数获得结果
    if (typeof info === 'function') {
      return save<T>(id, isLocal, info())
    }

    // 自定义，直接存入
    if (isReactive(info)) {
      return save<T>(id, isLocal, info as T)
    }

    // 对象， option 风格，有 state 属性
    if ((info as IStateCreateOption).state) {
      return save<T>(id, isLocal, OptionState<T>(id, info as IStateCreateOption))
    }
    
    // 没有 state 属性，info 视为 state
    return save<T>(id, isLocal, OptionState<T>(id, { state: info }))
    
}


/**
 * 保存局部状态的 BaseObject 类型
 * @param id 状态标识
 * @param state 状态，对象
 * @returns 
 */
export function saveBaseObject<T extends IObjectOrArray> (
    id: symbol | string,
    state: T
  ) {
    provide<T>(id as InjectionKey<BaseObject<T> & T>, state)
    return state as BaseObject<T> & T
  }

/**
* 保存局部状态的 BaseObject 类型
* @param id 状态标识
* @param state 状态，数组
* @returns 
*/
export function saveBaseArray<T> (
    id: symbol | string,
    state: T
  ) {
    provide<T>(id as InjectionKey<BaseArray<T> & T>, state)
    return state as BaseArray<T> & T
  }

/**
* 全局状态存入 store；局部状态存入 provide，返回状态
* @param id 状态标识
* @param isLocal 是否局部状态
* @param state 状态，对象或者数组
* @returns 返回状态
*/
export function save<T extends IObjectOrArray>(
  id: symbol | string,
  isLocal: boolean,
  state: T
) {
  // 判断是否全局状态
  if (isLocal) {
    // 局部状态，使用 provide 注入，我发现了，存入的时候不用带类型。
    if ((state as IState).$isObject) {
      return saveBaseObject<T>(id, state)
    } else if ((state as IState).$isArray) {
      return saveBaseArray<T>(id, state)
    }
    // setup 
    provide<T>(id as InjectionKey<T>, state)

  } else {
    // 全局状态，存入容器
    store[id] = state
  }
  return state as T & IState
}